package com.tianji.learning.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.dto.course.CourseFullInfoDTO;
import com.tianji.api.dto.leanring.LearningLessonDTO;
import com.tianji.api.dto.leanring.LearningRecordDTO;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.exceptions.DbException;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.dto.LearningRecordFormDTO;
import com.tianji.learning.domain.po.LearningLesson;
import com.tianji.learning.domain.po.LearningRecord;
import com.tianji.learning.enums.SectionType;
import com.tianji.learning.mapper.LearningRecordMapper;
import com.tianji.learning.service.ILearningLessonService;
import com.tianji.learning.service.ILearningRecordService;
import com.tianji.learning.utils.LearningRecordDelayTaskHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.validation.constraints.NotNull;
import java.util.List;

import static com.tianji.learning.enums.LessonStatus.*;

/**
 * <p>
 * 学习记录表 服务实现类
 * </p>
 *
 * @author 老李头儿
 * @since 2025-03-24
 */
@Service
public class LearningRecordServiceImpl extends ServiceImpl<LearningRecordMapper, LearningRecord> implements ILearningRecordService {
    @Autowired
    private ILearningLessonService lessonService;

    @Autowired
    private CourseClient courseClient;

    @Autowired
    private LearningRecordDelayTaskHandler taskHandler;

    /**
     * @param courseId
     * @Description 查询指定课程的学习记录
     * @Author 老李头儿
     * @Date 2025年03月24 15:39:06
     * @Return {@link LearningLessonDTO}
     **/
    @Override
    public LearningLessonDTO queryLearningRecordByCourse(Long courseId) {
        //1.根据用户id与课程id查询学习课表
        LearningLesson lesson = this.lessonService.lambdaQuery()
                .eq(LearningLesson::getCourseId, courseId)
                .eq(LearningLesson::getUserId, UserContext.getUser())
                .one();
        //2.拷贝数据
        LearningLessonDTO learningLessonDTO = BeanUtil.toBean(lesson, LearningLessonDTO.class);

        //3.根据课表id查询学习记录
        List<LearningRecord> learningRecords = this.lambdaQuery()
                .eq(LearningRecord::getLessonId, lesson.getId())
                .list();
        //4.拷贝数据
        List<LearningRecordDTO> learningRecordDTOS = BeanUtil.copyToList(learningRecords, LearningRecordDTO.class);

        learningLessonDTO.setRecords(learningRecordDTOS);
        return learningLessonDTO;
    }

    /**
     * @param learningRecordFormDTO
     * @Description 提交学习记录
     */
    @Override
    public void addLearningRecord(LearningRecordFormDTO learningRecordFormDTO) {
        // 1.获取登录用户
        Long userId = UserContext.getUser();
        // 2.处理学习记录
        boolean firstFinished = false;
        if (learningRecordFormDTO.getSectionType() == SectionType.VIDEO) {
            // 2.1.处理视频
            firstFinished = handleVideoRecord(userId, learningRecordFormDTO);
        } else {
            // 2.2.处理考试
            firstFinished = handleExamRecord(userId, learningRecordFormDTO);
        }
        //如果是非第一次完成就不进行课表处理
        if (!firstFinished && learningRecordFormDTO.getDuration() == -1) {
            return;
        }
        // 3.处理课表数据
        handleLearningLessonsChanges(learningRecordFormDTO, firstFinished);
    }

    /**
     * 处理课表数据
     *
     * @param learningRecordFormDTO
     * @param firstFinished
     */
    private void handleLearningLessonsChanges(LearningRecordFormDTO learningRecordFormDTO, boolean firstFinished) {
        // 1.查询课表
        LearningLesson lesson = lessonService.getById(learningRecordFormDTO.getLessonId());
        if (lesson == null) {
            throw new BizIllegalException("课程不存在，无法更新数据！");
        }
        boolean allLearned = false;
        //2.判断是否有新的完成小节
        if (firstFinished) {
            // 3.如果有新完成的小节，则需要查询课程数据
            CourseFullInfoDTO cInfo = courseClient.getCourseInfoById(lesson.getCourseId(), false, false);
            if (cInfo == null) {
                throw new BizIllegalException("课程不存在，无法更新数据！");
            }
            // 4.比较课程是否全部学完：已学习小节 >= 课程总小节
            allLearned = lesson.getLearnedSections() + 1 >= cInfo.getSectionNum();
        }
        //更新课表
        boolean updateResult = this.lessonService.lambdaUpdate()
                .set(LearningLesson::getLatestSectionId, learningRecordFormDTO.getSectionId()) // 更新最新学过的小节ID
                .set(LearningLesson::getLatestLearnTime, learningRecordFormDTO.getCommitTime()) // 更新最新学过的时间
                //.set(firstFinished, LearningLesson::getLearnedSections, lesson.getLearnedSections() + 1)
                .setSql(firstFinished, "learned_sections = learned_sections + 1")  // 更新已学习小节数+1 update table set {...} where ...
                .set(lesson.getStatus() == NOT_BEGIN, LearningLesson::getStatus, LEARNING)
                .set(allLearned, LearningLesson::getStatus, FINISHED) // 更新课表状态为已学完
                .eq(LearningLesson::getId, lesson.getId())
                .update();

        if (!updateResult) {
            throw new DbException("更新课表失败");
        }
    }

    /**
     * 处理视频
     *
     * @param userId
     * @param learningRecordFormDTO
     * @return
     */
    private boolean handleVideoRecord(Long userId, LearningRecordFormDTO learningRecordFormDTO) {
        //1.判断该视频小节是否存在观看记录
        LearningRecord learningRecord = queryOldRecord(learningRecordFormDTO.getLessonId(), learningRecordFormDTO.getSectionId());
        if (learningRecord == null) {
            //说明是首次提交记录，则新增一条记录
            //1.拷贝属性
            learningRecord = BeanUtil.toBean(learningRecordFormDTO, LearningRecord.class);
            //2.填充缺失数据
            learningRecord.setUserId(userId);
            //3.保存数据
            boolean success = save(learningRecord);
            if (!success) {
                // 处理新增失败的情况，比如记录日志或抛出自定义异常
                throw new RuntimeException("学习记录新增失败");
            }
            return false;
        }

        //2.判断是否是第一次完成该小结
        boolean firstFinished = !learningRecord.getFinished() && learningRecordFormDTO.getMoment() * 2 >= learningRecordFormDTO.getDuration();

        //如果是非第一次学完，将学习记录暂存至redis，并且提交一个延迟任务
        if (!firstFinished) {
            LearningRecord record = new LearningRecord();
            record.setLessonId(learningRecordFormDTO.getLessonId());
            record.setSectionId(learningRecordFormDTO.getSectionId());
            record.setId(learningRecord.getId());
            record.setMoment(learningRecordFormDTO.getMoment());
            record.setFinished(learningRecord.getFinished());
            taskHandler.addLearningRecordDelayCheckTask(record);
            learningRecordFormDTO.setDuration(-1);
            return false;
        }
        //第一次学完
        //3,更新数据
        boolean update = this.lambdaUpdate()
                .set(LearningRecord::getMoment, learningRecordFormDTO.getMoment())
                .set(LearningRecord::getFinishTime, learningRecordFormDTO.getCommitTime())
                .set(LearningRecord::getFinished, true)
                .eq(LearningRecord::getId, learningRecord.getId())
                .update();

        if (!update) {
            throw new DbException("更新学习记录失败！");
        }
        //清理redis缓存
        taskHandler.clearLearningRecordDelayCheckTaskCache(learningRecordFormDTO.getLessonId(), learningRecordFormDTO.getSectionId());
        return firstFinished;
    }

    /**
     * 判断该视频小节是否存在观看记录
     *
     * @param lessonId
     * @param sectionId
     * @return
     */
    private LearningRecord queryOldRecord(@NotNull(message = "课表id不能为空") Long lessonId, @NotNull(message = "节的id不能为空") Long sectionId) {
        //查询缓存中是否有该记录
        LearningRecord oldRecord = taskHandler.readLearningRecordFromCache(lessonId, sectionId);
        //如果有直接返回
        if (ObjectUtil.isNotEmpty(oldRecord)) {
            return oldRecord;
        }
        //如果没有，则查询数据库。并写入缓存
        LearningRecord learningRecord = lambdaQuery()
                .eq(LearningRecord::getLessonId, lessonId)
                .eq(LearningRecord::getSectionId, sectionId)
                .one();
        if (ObjectUtil.isEmpty(learningRecord)) {
            return null;
        }
        taskHandler.writeLearningRecordToCache(learningRecord);

        return learningRecord;
    }

    /**
     * 处理考试
     *
     * @param userId
     * @param learningRecordFormDTO
     * @return
     */
    private boolean handleExamRecord(Long userId, LearningRecordFormDTO learningRecordFormDTO) {
        //1.拷贝属性
        LearningRecord learningRecord = BeanUtil.toBean(learningRecordFormDTO, LearningRecord.class);
        //2.填充缺失数据
        learningRecord.setUserId(userId);
        learningRecord.setFinished(true);
        learningRecord.setFinishTime(learningRecordFormDTO.getCommitTime());
        //3.保存数据
        boolean success = save(learningRecord);
        if (!success) {
            // 处理新增失败的情况，比如记录日志或抛出自定义异常
            throw new RuntimeException("学习记录新增失败");
        }
        //4.返回true，代表首次学习完
        return true;
    }


}
